package com.mfhcd.facepay.network;

import android.content.Context;
import android.view.View;

import com.alibaba.android.arouter.launcher.ARouter;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.mfhcd.facepay.App;
import com.mfhcd.facepay.base.NavigationController;
import com.mfhcd.facepay.constant.ArouterUrl;
import com.mfhcd.facepay.converter.ErrorGsonConverterFactory;
import com.mfhcd.facepay.global.AppConfig;
import com.mfhcd.facepay.interceptor.HttpLoggingInterceptor;
import com.mfhcd.facepay.interceptor.PassHttpLoggingInterceptor;
import com.mfhcd.facepay.network.callback.CallBack;
import com.mfhcd.facepay.utils.DialogUtils;
import com.mfhcd.facepay.utils.LogUtil;
import com.mfhcd.facepay.utils.SPUtils;
import com.trello.rxlifecycle3.components.support.RxAppCompatActivity;

import java.io.File;
import java.net.Proxy;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.Collection;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;

import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Cache;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;

import static com.mfhcd.facepay.global.ServerUrl.BASE_URL;
import static com.mfhcd.facepay.global.ServerUrl.PASS_BASE_URL;

/**
 * Author：石强
 * E-Mail: shiqiang@mfhcd.com
 * Date：2019-09-06
 * 版权所有 © 现代金融控股（成都）有限公司
 */
public class NetworkUtils {
    private static final int DEFAULT_CONNECT_TIME = 30;
    private static final int DEFAULT_WRITE_TIME = 30;
    private static final int DEFAULT_READ_TIME = 30;
    private static Retrofit retrofit;
    private volatile static NetworkUtils mNetworkUtils;
    private volatile static NetworkUtils mPaasNetworkUtils;
    private boolean saasRequest = true;
    private Gson mGson;
    private File mCcacheFile = null;
    private Cache mCache = null;

    private NetworkUtils() {
        mGson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
        //创建缓存路径
        mCcacheFile = new File(App.getContext().getCacheDir(), "HttpCache");
        //100Mb
        mCache = new Cache(mCcacheFile, 1024 * 1024 * 100);
    }

    public boolean isSaasRequest() {
        return saasRequest;
    }

    public void setSaasRequest(boolean saasRequest) {
        this.saasRequest = saasRequest;
    }

    private OkHttpClient getOkHttpClient() {
        LogUtil.d("saasRequest = " + saasRequest);
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .proxy(Proxy.NO_PROXY)
                //连接超时时间
                .connectTimeout(DEFAULT_CONNECT_TIME, TimeUnit.SECONDS)
                //设置写操作超时时间
                .writeTimeout(DEFAULT_WRITE_TIME, TimeUnit.SECONDS)
                //设置读操作超时时间
                .readTimeout(DEFAULT_READ_TIME, TimeUnit.SECONDS)
                .hostnameVerifier(new UnSafeHostnameVerifier())
                .cookieJar(new CookieManager())
                .addInterceptor(isSaasRequest() ? new HttpLoggingInterceptor() : new PassHttpLoggingInterceptor())
                .cache(mCache)
                .build();
        return okHttpClient;
    }

    private NetworkUtils builder() {
        retrofit = new Retrofit.Builder()
                //设置使用okhttp网络请求
                .client(getOkHttpClient())
                //设置服务器路径
                .baseUrl(isSaasRequest() ? BASE_URL : PASS_BASE_URL)
                //添加转化库，默认是Gson
                .addConverterFactory(ErrorGsonConverterFactory.create(mGson))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
        return this;
    }

    /**
     * 通过service的Url注解设置每个接口不同的url
     */
    @Deprecated
    public NetworkUtils builderByUrl(String baseUrl) {
        LogUtil.d("baseUrl = " + baseUrl);
        retrofit = new Retrofit.Builder()
                //设置使用okhttp网络请求
                .client(getOkHttpClient())
                //设置服务器路径
                .baseUrl(baseUrl)
                //添加转化库，默认是Gson
                .addConverterFactory(ErrorGsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
        return this;
    }

    //使用内置证书
    private static SSLSocketFactory getSSLSocketFactory_Certificate(Context context) {
        try {
            //获取X.509格式的内置证书
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            Collection<? extends Certificate> cers = certificateFactory.generateCertificates(context.getAssets().open("mposapp.cer"));
            int index = 0;
            for (Certificate certificate : cers) {
                String certificateAlias = Integer.toString(index++);
                keyStore.setCertificateEntry(certificateAlias, certificate);
            }
            //用这个KeyStore去引导生成的TrustManager来提供验证
            final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            //用TrustManager生成SSLContext
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
            //SSLContext返回SSLSocketFactory
            return sslContext.getSocketFactory();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static class SingletonHolder {
        private static final NetworkUtils INSTANCE = new NetworkUtils();
    }

    public static NetworkUtils getInstance() {
        if (mNetworkUtils == null) {
            synchronized (NetworkUtils.class) {
                if (mNetworkUtils == null) {
                    mNetworkUtils = new NetworkUtils();
                    mNetworkUtils.setSaasRequest(true);
                    //初始化网络对象
                    mNetworkUtils.builder();
                }
            }
        }
        return mNetworkUtils;
    }

    public static NetworkUtils getPaasInstance() {
        if (mPaasNetworkUtils == null) {
            synchronized (NetworkUtils.class) {
                if (mPaasNetworkUtils == null) {
                    mPaasNetworkUtils = new NetworkUtils();
                    mNetworkUtils.setSaasRequest(false);
                    //初始化网络对象
                    mNetworkUtils.builder();
                }
            }
        }
        return mNetworkUtils;
    }

    public <T> T create(Class<T> service) {
        return retrofit.create(service);
    }

    public <T> void setSubscribe(Context context, Observable<T> observable, CallBack<T> callBack) {
        observable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .compose(((RxAppCompatActivity) context).bindToLifecycle())
                .subscribe(new Observer<T>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                    }

                    @Override
                    public void onNext(T t) {
                        callBack.onSuccess(t);
                    }

                    @Override
                    public void onError(Throwable e) {
                        if (AppConfig.DEBUG) {
                            e.printStackTrace();
                        }
                        if (e instanceof NetErrorException) {
                            //处理token失效
                            if (((NetErrorException) e).getErrorType() == NetErrorException.TOKEN_INVALIDATE) {
                                //清除登录信息
//                            SPUtils.clearLoginData();
                                //弹框，点击确定时跳转登录。
                                DialogUtils.showConfirmDialog(context, "提示", "当前登录已失效，请重新登录。", new DialogUtils.DialogClickListener() {
                                    @Override
                                    public void onConfirmClick(View view) {
                                        //back to Main
                                        NavigationController.getInstance().popToRoot();
                                        //navi to login
                                        ARouter.getInstance().build(ArouterUrl.ACTIVITY_LOGIN).navigation();
                                    }

                                    @Override
                                    public void onCancelClick() {
                                    }
                                });
                            } else {
                                //处理其他错误
                                callBack.onError(((NetErrorException) e).getErrorCode(), e.getMessage());
                            }

                        } else {
                            callBack.onError(String.valueOf(NetErrorException.OTHER), e.getMessage());
                        }
                    }

                    @Override
                    public void onComplete() {
                    }
                });
    }
}
